(function(){
    
    var MobileUx = {
        
        /*
         * 用于测试设备属性
         */
        platforms : [{
                property: 'platform',
                regex: /iPhone/i,
                identity: 'iPhone'
            },{
                property: 'platform',
                regex: /iPod/i,
                identity: 'iPod'
            },{
                property: 'userAgent',
                regex: /iPad/i,
                identity: 'iPad'
            },{
                property: 'userAgent',
                regex: /Blackberry/i,
                identity: 'Blackberry'
            },{
                property: 'userAgent',
                regex: /Android/i,
                identity: 'Android'
            },{
                property: 'platform',
                regex: /Mac/i,
                identity: 'Mac'
            },{
                property: 'platform',
                regex: /Win/i,
                identity: 'Windows'
            },{
                property: 'platform',
                regex: /Linux/i,
                identity: 'Linux'
        }],
        
        /*
         * 用于测试设备属性
         */
        tests: [{
            identity: 'CSS3DTransform',
            fn: function() {
                return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
            }
        }],
        
        init: function(){
            this.initEventName();
            this.initMobileProperty();
            this.initPropertyOnReady();
            this.initRangeClick();
            if($.support.touch){
                this.setupForMobile();
            }else{
                this.setupForPc();
            }
            this.platforms.splice(0);
            this.initSwipe();
            this.initTranslate();
        },
        
        /*initPinch: function(){
            $.each( "pinchstart pinch pinchend".split(" "), function(i, name) {
                $.fn[name] = function(fn) {
                    return fn ? this.on(name, fn) : this.trigger(name);
                };
                $.attrFn[name] = true;
            });
            
            $.event.special.pinchend = {
            
                setup: function(){
                    if(!$.support.touch){
                        return false;
                    }
                    var $this = $(this);
                    var data  = {};
                    function getInfo(p1, p2){
                        var deltaX        = p1.pageX - p2.pageX;
                        var deltaY        = p1.pageY - p2.pageY;
                        var distance      = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
                        var pinchStarted  = data.pinchStarted;
                        var startDistance = pinchStarted ? data.startDistance : distance;
                        var info     = {
                            startX        : p1.pageX,
                            startY        : p1.pageY,
                            currentX      : p2.pageX,
                            currentY      : p2.pageY,
                            deltaX        : deltaX,
                            deltaY        : deltaY,
                            distance      : distance,
                            startDistance : startDistance,
                            scale         : distance / startDistance
                        }
                        data.lastInfo     = info;
                        return info;
                    }
                    $this.on('touchstart', function(event){
                        var touches           = event.originalEvent.touches;
                        if(data.pinchStarted){
                            data.pinchStarted = false;
                            $this.trigger($.Event("pinchend", data.lastInfo));
                        }
                        if( touches.length == 2 ){
                            var info          = getInfo(touches[0], touches[1]);
                            data.startDistance= info.startDistance;
                            data.pinchStarted = true;
                            $this.trigger( $.Event("pinchstart", info) );
                        }
                    });
                    $this.on('touchmove', function(event){
                        var touches           = event.originalEvent.touches;
                        if( !data.pinchStarted || touches.length != 2 ){
                            return;
                        }
                        var info              = getInfo(touches[0], touches[1]);
                        $this.trigger( $.Event("pinch",          info) );
                    });
                    $this.on('touchend',  function(event){
                        var originalEvent = event.originalEvent;
                        var touches       = originalEvent.changedTouches;
                        if(data.pinchStarted){
                            data.pinchStarted = false;
                            $this.trigger($.Event("pinchend", data.lastInfo));     
                        }
                    });
                }
            }
        },*/
        
        initSwipe: function(){
            $.event.special.swipe =  {
            setup : function(){
        		var thisObject = this,
        			$this = $( thisObject ),
                    supportTouch = $.support.touch,
                	touchStartEvent = supportTouch ? "touchstart" : "mousedown",
                	touchStopEvent = supportTouch ? "touchend" : "mouseup",
                	touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
        		$this.on( touchStartEvent, function( event ) {
        			var data = event.originalEvent.touches ?
        								event.originalEvent.touches[ 0 ] : event,
        				start = {
        					time: ( new Date() ).getTime(),
        					coords: [ data.pageX, data.pageY ],
        					origin: $( event.target )
        				},
        				stop;
        
        			function moveHandler( event ) {
        				if ( !start ) {
        					return;
        				}else if( event.originalEvent.touches && event.originalEvent.touches.length >= 2 ){
        				    return;
        				}
        
        				var data = event.originalEvent.touches ?
        						event.originalEvent.touches[ 0 ] : event;
        
        				stop = {
        					time: ( new Date() ).getTime(),
        					coords: [ data.pageX, data.pageY ]
        				};
        
        				// prevent scrolling
        				if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
        					event.preventDefault();
        				}
        			}
        
        			$this.on( touchMoveEvent, moveHandler )
        				.one( touchStopEvent, function( event ) {
        					$this.off( touchMoveEvent, moveHandler );
                            if( event.originalEvent.changedTouches && event.originalEvent.changedTouches.length >= 2 ){
            				    return;
                            }else if ( start && stop ) {
        						if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
        								Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
        								Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
        
        							start.origin.trigger( "swipe" )
        								.trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
        						}
        					}
        					start = stop = undefined;
        				});
        		});
        	}}
            
            
        },
        
        initTranslate: function(){
            /*
             * 设置元素偏移
             */
            $.fn.translate = function(x, y){
                if(!this.length){
                    return;
                }
                x = (x ? (x + 'px') : 0);
                y = (y ? (y + 'px') : 0);
                this[0].style.webkitTransform = 'translate(' + x + ',' + y + ')';
            };
        },
        
        /*
         * 一个特殊点击事件，目的是为了解除滑动以及滚动时的干扰
         * 按下后，x,y移动距离不能超过5px，且按下与松开之间的时间差不能超过200ms，当时间条件以及距离条件都满足的时候出发rangeclick事件 
         */
        initRangeClick: function(){
            $.event.special.rangeclick = {
                setup: function(){
                    var $this       = $(this);
                    var distance    = 5;
                    var timeMax     = 200;
                    var started, useTime, startX, startY;
                    function endFn(e){
                        started     = false;
                        useTime     = ((new Date()).getTime() - time);
                        var touches = e.originalEvent.changedTouches;
                        var touch   = touches ? touches[0] : e;
                        
                        if( Math.abs(startX - touch.pageX) <= distance && 
                            Math.abs(startY - touch.pageY) <= distance && 
                            useTime <= timeMax ){
                            var newEvent  = new $.Event(e.originalEvent, e);
                            newEvent.type = 'rangeclick';
                            $.event.trigger(newEvent, null, $this[0]);
                        }
                    }
                    $this.on($.support.touchstart,function(e){
                        var touches = e.originalEvent.touches;
                        if(started){
                            endFn(e);
                        }
                        var touch;
                        if(!touches || touches.length == 1){
                            touch   = touches ? touches[0] : e;
                            started = true;
                            time    = (new Date()).getTime();
                            startX  = touch.pageX;
                            startY  = touch.pageY;
                        }
                    });
                    $this.on($.support.touchstop, function(e){
                        if(started){
                            endFn(e);
                        }
                    });
                }
            };
        },

        initPropertyOnReady: function(){
            var that          = this;
            $(function(){
                var doc       = document;
                var div       = doc.createElement('div');
                div.innerHTML = ['<div style="height:30px;width:50px;">', '<div style="height:20px;width:20px;"></div>', '</div>', '<div style="float:left; background-color:transparent;"></div>'].join('');
                doc.body.appendChild(div);
                for (i = 0, ln = that.tests.length; i < ln; i++){
                    test      = that.tests[i];
                    $.support[test.identity] = test.fn.call(this, doc, div);
                }
                doc.body.removeChild(div);
                that = div = doc = null;
            });
        },
        
        initMobileProperty: function(){
            var navigator = navigator || window.navigator;
            var is        = {};
            var platform, i, test;
            for (i = 0, ln = this.platforms.length; i < ln; i++) {
                platform  = this.platforms[i];
                is[platform.identity] = platform.regex.test(navigator[platform.property]);
            }
            is.Desktop    = is.Mac || is.Windows || (is.Linux && !is.Android);
            is.iOS        = is.iPhone || is.iPad || is.iPod;
            is.Standalone = !!navigator.standalone;
            i              = is.Android && (/Android\s(\d+\.\d+)/.exec(navigator.userAgent));
            if (i) {
                is.AndroidVersion      = i[1];
                is.AndroidMajorVersion = parseInt(i[1], 10);
            }
            is.Tablet     = is.iPad || (is.Android && is.AndroidMajorVersion === 3);
            is.Phone      = !is.Desktop && !is.Tablet;
            is.MultiTouch = !is.Blackberry && !is.Desktop && !(is.Android && is.AndroidVersion < 3);
            $.support.is  = is;
        },
        
        initEventName: function(){
            var supportTouch =  $.support.touch;
            $.extend($.support, {
                mousedown    : supportTouch ? "vmousedown"  : "mousedown",
                mouseup      : supportTouch ? "vmouseup"    : "mouseup",
                mouseout     : supportTouch ? "vmouseout"   : "mouseout",
                click        : supportTouch ? "vclick"      : "click",
                dblclick     : supportTouch ? "vdblclick"   : "dblclick",
                mousecancel  : supportTouch ? "vmousecancel": "mousecancel",
                touchstart   : supportTouch ? "touchstart"  : 'vtouchstart',
                touchstop    : supportTouch ? "touchend"    : 'vtouchend',
                touchmove    : supportTouch ? "touchmove"   : 'vtouchmove'
            });
        },
        
        initPropertyFn: function(){},
        
        setupForPc: function(){
            this.readyMousecancel();
            this.readyTouch();
        },
        
        setupForMobile: function(){
            this.initPinch();
            this.readyVdblclick();
            this.addMeta();
            this.preventDefaultOnIOS();
        },
        
        readyMousecancel: function(){
            $.event.special.mousecancel = {
                
                setup: function() {
                    var $this = $(this);
                    $this.on('mousedown', function(event){
                        var startX = event.pageX;
                        var startY = event.pageY;
                        function handleCancel(){
                            clearHandler();
                            $this.trigger("mousecancel");
                        };
                        function clearHandler(){
                            $this.off('mousemove');
                            $this.off('mouseup');
                            $this.off('mouselevel');
                        };
                        $this.on('mousemove', function(e){
                            var moveThreshold = $.vmouse.moveDistanceThreshold;
                            if ( Math.abs(e.pageX - startX) > moveThreshold || Math.abs(e.pageY - startY) > moveThreshold ) {
                                handleCancel();
                            }
                        });
                        $this.on('mouseup',   clearHandler);
                        $this.on('mouseleave',handleCancel);
                    });
                }
                
            };
        },
        
        /*
         * 原有的vtouchstart触发后，若移动到元素外部，会导致vtouchend接收不到，为了解决这个问题，做了一些完善处理 
         */
        readyTouch : function(){
            var targets    = [];
            var startEvent = false;
            var $curEl     = false;
            
            ['vtouchstart', 'vtouchmove', 'vtouchend'].forEach(function(type){
                $.event.special[type] = {
                    setup: function(){
                        var $this = $(this);
                        if( !$this.data('vt') ){
                            $this.data('vt', true);
                            targets.push($this);
                        }
                    }
                };
            });
            
            function trigger(type, event){
                if($curEl){
                    var newEvent  = new $.Event(event.originalEvent, event);
                    newEvent.type = type;
                    $.event.trigger(newEvent, null, $curEl[0]);
                }
            }
            
            function handleTouchStart(e){
                if(startEvent){
                    handleTouchEnd(e);
                }
                startEvent    = true;
                var target    = e.target;
                $curEl        = false;
                var len       = targets.length;
                var i;
                while(target){
                    for(i = 0; i < len; i++){
                        if( target === targets[i][0] ){
                            $curEl = targets[i];
                            break;
                        }
                    }
                    if($curEl){//防止事件重复触发
                        break;
                    }
                    target = target.parentNode;
                }
                trigger('vtouchstart', e);
                target     = null;
            }
            
            function handleTouchMove(e){
                if(!startEvent){
                    return;
                }
                if($curEl){
                    trigger('vtouchmove', e);
                }
            }
            
            function handleTouchEnd(e){
                if(!startEvent){
                    return;
                }
                if($curEl){
                    trigger('vtouchend', e);
                }
                $curEl     = false;
                startEvent = false;
            }
            
            $(document).
                on( "mousedown", handleTouchStart).
                on( "mousemove", handleTouchMove ).
                on( "mouseup",   handleTouchEnd  );
        },
        
        /*
         * 移动设备上的双击事件
         
        readyVdblclick:function(){
            $.event.special.vdblclick = {
                setup: function() {
                    var $this = $(this);
                    $this.on('vclick', function(e){
                        var t0 = $this.data('preClickTime');
                        var t1 = e.timeStamp;
                        if(!t0 || t1 - t0 >= 200){
                            t0 = t1;
                        }else{
                            var props  = $.extend({}, e);
                            props.type = 'vdblclick';
                            $this.trigger(props);
                            t0 = null;
                        }
                        $this.data('preClickTime', t0);
                    });
                }
            }
        },*/
        
        _createMeta: function(attrs){
            var meta  = document.createElement('meta');
            for(var i in attrs){
                meta.setAttribute(i, attrs[i]);
            }
            return meta;
        },
        
        addMeta: function(){
            var head  = document.getElementsByTagName('head')[0];
            head.appendChild(this._createMeta({
                "name"     : "viewport",
                "content"  : "width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0;"
            }));
            if($.support.is.iOS){
                head.appendChild(this._createMeta({
                    "name"     : "apple-mobile-web-app-capable",
                    "content"  : "yes"
                }));
                head.appendChild(this._createMeta({
                    "name"     : "format-detection",
                    "content"  : "telephone=no"
                }));
            }
        },
        
        preventDefaultOnIOS: function(){
            document.addEventListener( 'touchmove', function ( event ) {
                event.preventDefault();
            }, false);
        }
    };
    
    MobileUx.init();
    MobileUx = null;
    
})();